package net.wangds.dymodel.query;

import net.wangds.dymodel.ddl.DyModelDdlComp;
import net.wangds.dymodel.meta.entity.DyModelDefEntity;
import net.wangds.dymodel.meta.entity.DyModelPropDefEntity;
import net.wangds.dymodel.utls.DynamicModelUtils;
import net.wangds.jdbc.comp.jdbc.JdbcComp;
import net.wangds.log.helper.LogHelper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * .
 * <p></p>
 *
 * @author 王东石 2021/2/16 3:38.
 */
@Component
public class QueryParse {


    @Autowired
    private JdbcComp mmJdbc;


    @Autowired
    private DyModelDdlComp mmCmpMdl;

    @Autowired
    private ConditionParse mmCondParse;

    /**
     * 查询id.
     * @param id id.
     * @param model 模型.
     * @param clz 输出类型.
     * @param <T> 输出类型.
     * @return 结果.
     */
    public <T> T findById(String id, DyModelDefEntity model, Class<T> clz){
        String selectSql = "select * from "+ DynamicModelUtils.toFullTableName(model)+" where id=?";
        return (mmJdbc.executeQuery(selectSql, new Object[]{id}, clz)
                .stream().findFirst().orElse(null));
    }

    /**
     * 是否存在.
     * @param id id.
     * @param model 模型.
     * @return 是否存在.
     */
    public boolean existsById(String id, DyModelDefEntity model){
        String sql = "select count(*) from " +DynamicModelUtils.toFullTableName(model)+" where id=?";
        return mmJdbc.executeQueryAsLong(sql, new Object[]{id})>0;
    }


    public long total(Query q){

        if(q.getModel()==null||CollectionUtils.isEmpty(q.getDisplayColumns())){
            initQuery(q);
        }
        //TODO 改预处理
        String sql = "SELECT count(*) as total FROM " +
                DynamicModelUtils.toFullTableName(q.getModel()) +
                " WHERE " + mmCondParse.toWhere(q.getCondition());
        return mmJdbc.executeQueryAsLong(sql, new Object[0]);
    }

    @SuppressWarnings("unchecked")
    public <T> Page<T> select(Query q){
        if(q==null){
            return new PageImpl<>(Collections.emptyList(), PageRequest.of(1,100),0);
        }

        if(q.getModel()==null){
            initQuery(q);
        }

        int pi = Math.max(q.getPageIndex(), 1)-1;
        int ps = q.getPageIndex()<=0?-1:Math.max(q.getPageSize(), 10);
        DyModelDefEntity mdl = q.getModel();
        StringBuffer sql = new StringBuffer();
        sql.append("SELECT * ")
                .append(" FROM ").append(DynamicModelUtils.toFullTableName(mdl))
        .append(" WHERE ").append(mmCondParse.toWhere(q.getCondition()))
                ;

        List<OrderBy> ods = q.getOrderBy();
        if(!CollectionUtils.isEmpty(ods)){
            sql.append(" ORDER BY ");
            Collections.sort(ods, Comparator.comparingLong(OrderBy::getSeq));
            ods.forEach(c-> sql.append(c.getColumn()==null?c.getColumnName():c.getColumn().getNameEn()).append(" ")
                    .append(c.getDirect().name())
                    .append(","));
            if(StringUtils.endsWith(sql, ",")){
                sql.deleteCharAt(sql.length()-1);
            }
        }


        String cmd = sql.toString();
        LogHelper.dev("sql:"+cmd);
        Class<T> clz = (Class<T>) q.getModelClass();
        if(clz==null){
            clz= (Class<T>)HashMap.class;
        }
        if(ps==-1){
            List<T> list = mmJdbc.executeQuery(cmd, new Object[0], clz);
            long total = total(q);
            return new PageImpl<>(list, PageRequest.of(0, Math.max((int)total,1)), total);
        }else {
            return mmJdbc.executeQuery(cmd, new Object[0], PageRequest.of(pi, ps), clz);
        }
    }


    protected void initQuery(Query q){
        if(q==null||StringUtils.isBlank(q.getModelId())){
          return;
        }

        String moduleId = q.getModelId();

        mmCmpMdl.findModel(moduleId).ifPresent(mdl->{
            q.setModel(mdl);
            List<String> cols = q.getDisplayColumnIds();
            boolean bShowAll = CollectionUtils.isEmpty(cols);
            String[] displayColIds = cols!=null?(String[])cols.toArray():new String[0];

            List<DyModelPropDefEntity> fields = new ArrayList<>();

            List<OrderBy> orderbys = q.getOrderBy();

            mmCmpMdl.foreachField(mdl, f->{
                String id = f.getId();
                String name = f.getNameEn();
                String col = f.getColumnName();
                if(bShowAll
                        ||StringUtils.equalsAny(id, displayColIds)
                    ||StringUtils.equalsAny(name, displayColIds)
                        ||StringUtils.equalsAny(col, displayColIds)
                ){
                    fields.add(f);
                    Optional.ofNullable(orderbys).ifPresent(
                            os->os.stream().filter(o->{
                                String oid = o.getDyColumnId();
                                return StringUtils.equalsIgnoreCase(id,oid)
                                        ||StringUtils.equalsIgnoreCase(name, oid)
                                        ||StringUtils.equalsIgnoreCase(col, oid);
                            }).findFirst().ifPresent(c->c.setColumn(f)));
                }
            });
            q.setDisplayColumns(fields);

        });

    }



}
